package com.joymart.common.oss;


import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectRequest;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.apache.http.impl.client.BasicCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;


@Slf4j
@Service
public class OSSService {

    @Value("${oss.region}")
    private String region;

    @Value("${oss.endpoint}")
    private String endpoint;

    @Value("${oss.accessKeyId}")
    private String accessKeyId;

    @Value("${oss.accessSecret}")
    private String accessSecret;

    @Value("${oss.bucketName}")
    private String bucketName;

    private OSS client;

    @PostConstruct
    public void init() {

        DefaultCredentialProvider defaultCredentialProvider = CredentialsProviderFactory.newDefaultCredentialProvider(accessKeyId, accessSecret);

        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS oss = OSSClientBuilder.create().endpoint(endpoint).credentialsProvider(defaultCredentialProvider).clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();
        client = oss;
        boolean existed = client.doesBucketExist(bucketName);
        if (existed) {
            log.info("OSSClient initialized successfully! ");
        } else {
            log.error("OSSClient initialized fail! ");
        }
    }

    @PreDestroy
    public void destroy() {
        if (this.client != null) {
            this.client.shutdown();
        }
    }

    /**
     * @param dir 设置上传到OSS文件的前缀，可置空此项。置空后，文件将上传至Bucket的根目录下。
     * @return
     */
    @SneakyThrows
    public Map<String, String> generateSignature(String dir, int fileSizeInMB) {

        long expireTime = 60;
        long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
        Date expiration = new Date(expireEndTime);

        PolicyConditions policyConds = new PolicyConditions();
        // PostObject请求最大可支持的文件大小为5 GB，即CONTENT_LENGTH_RANGE为5*1024*1024*1024。此处设置为5M
        policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, fileSizeInMB * 1024 * 1024);
        policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

        String postPolicy = client.generatePostPolicy(expiration, policyConds);
        byte[] binaryData = postPolicy.getBytes("utf-8");
        String accessId = accessKeyId;
        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
        String postSignature = client.calculatePostSignature(postPolicy);

        Map<String, String> map = new LinkedHashMap<>();

        map.put("Host", "https://" + bucketName + "." + endpoint);
        map.put("AccessKeyId", accessId);
        map.put("Policy", encodedPolicy);
        map.put("Signature", postSignature);
        return map;
    }


    public String upload(String filename, byte[] content) {
        try (ByteArrayInputStream stream = new ByteArrayInputStream(content)) {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filename, stream);
            client.putObject(putObjectRequest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "https://" + bucketName + "." + endpoint + "/" + filename;
    }
}
